package org.comix.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
 * 
 * @Creator paladin
 * @Created-date 2009-1-15
 */
public abstract class ClassUtil {

	protected static final Log logger = LogFactory.getLog(ClassUtil.class);

	public static <T> Field[] findDeclaredFields(Class<T> cls) {
		Field[] fs = cls.getDeclaredFields();
		for (int i = 0; i < fs.length; i++) {
			fs[i].setAccessible(true);
		}
		return fs;
	}

	public static <T> List<Field> findDeclaredField(Class<T> cls) {
		List<Field> retVal = new ArrayList<Field>();
		Field[] fields = cls.getDeclaredFields();

		for (int i = 0; i < fields.length; i++) {
			fields[i].setAccessible(true);
			retVal.add(fields[i]);
		}
		return retVal;
	}

	public static <T> List<Field> findDeclaredField(Class<T> cls, Class<? extends Annotation> annotationClass) {
		List<Field> fs = findDeclaredField(cls);

		for (Field f : fs) {
			if (f.getAnnotation(annotationClass) == null) {
				fs.remove(f);
			}
		}
		return fs;
	}

	public static Class<?> loadClass(String className) throws ClassNotFoundException {
		Class<?> cls = getDefaultClassLoader().loadClass(className);

		if (cls == null) {
			cls = ClassUtil.class.getClassLoader().loadClass(className);
		}
		return cls;
	}

	public static Object instance(String className) throws ClassNotFoundException, InstantiationException,
			IllegalAccessException {
		Class<?> cls = loadClass(className);
		return cls.newInstance();
	}

	/**
	 * 鑾峰緱杩涜娉ㄩ噴鐨勫瓧娈�
	 * 
	 * @param cls
	 * @param annoCls
	 * @return
	 */
	public static Field[] getDeclaredField(Class<?> cls, Class<? extends Annotation> annoCls) {
		Field[] fields = cls.getDeclaredFields();

		List<Field> ls = new ArrayList<Field>();

		for (int i = 0; i < fields.length; i++) {
			if (fields[i].getAnnotation(annoCls) == null) {
				continue;
			}
			fields[i].setAccessible(true);
			ls.add(fields[i]);
		}

		return ls.toArray(new Field[] {});
	}

	/**
	 * 鑾峰緱涓�涓被澹版槑鐨勫瓧娈�
	 * 
	 * @param cls
	 * @return
	 */
	public static Field[] getDeclaredField(Class<?> cls) {
		Field[] fields = cls.getDeclaredFields();
		for (int i = 0; i < fields.length; i++) {
			fields[i].setAccessible(true);
		}
		return fields;
	}

	/**
	 * 鑾峰緱涓�涓被鐨勫寘鍚�
	 * 
	 * @param className
	 * @return
	 */
	public static String getPackageName(String className) {
		int index = className.lastIndexOf(".");
		if (index == -1) {
			return "";
		}
		String packageName = className.substring(0, index);

		return packageName;
	}

	/**
	 * 鑾峰緱涓�涓璞＄殑绫诲悕绉�
	 * 
	 * @param objBean
	 * @return
	 */
	public static String getShortName(Object objBean) {
		if (objBean == null) {
			return "";
		}
		return objBean.getClass().getSimpleName();
	}

	/**
	 * 瀹炰緥鍖栦竴涓被瀵硅薄
	 * 
	 * @param <T>
	 * @param cls
	 * @return
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 */
	public static <T> T instantiateClass(Class<T> cls) throws InstantiationException, IllegalAccessException {
		return cls.newInstance();
	}

	/**
	 * 鏍规嵁鏋勯�犳硶瀹炰緥鍖栦竴涓被
	 * 
	 * @param <T>
	 * @param constructor
	 * @param args
	 * @return
	 * @throws IllegalArgumentException
	 * @throws InstantiationException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static <T> T instantiateClass(Constructor<T> constructor, Object[] args) throws IllegalArgumentException,
			InstantiationException, IllegalAccessException, InvocationTargetException {
		return constructor.newInstance(args);
	}

	/**
	 * 鍔犺浇涓�涓被
	 * 
	 * @param className
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static Class<?> forName(String className) throws ClassNotFoundException {
		return forName(className, getDefaultClassLoader());
	}

	/**
	 * 鍔犺浇涓�涓被
	 * 
	 * @param className
	 * @param classLoader
	 * @return
	 * @throws ClassNotFoundException
	 */
	public static Class<?> forName(String className, ClassLoader classLoader) throws ClassNotFoundException {
		Class<?> cls = null;

		try {
			cls = classLoader.loadClass(className);
			return cls;
		} catch (ClassNotFoundException e) {
			try {
				cls = getDefaultClassLoader().loadClass(className);
				return cls;
			} catch (ClassNotFoundException e1) {
				throw e;
			}
		}
	}

	/**
	 * 鑾峰緱绫荤殑鏋勯�犳硶
	 * 
	 * @param cls
	 * @param argTypes
	 * @return
	 * @throws NoSuchMethodException
	 */
	public static Constructor<?> getConstructorIfAvailable(Class<?> cls, Class<?>[] argTypes)
			throws NoSuchMethodException {
		Constructor<?> constructor = null;

		try {
			constructor = cls.getConstructor(argTypes);
		} catch (NoSuchMethodException e) {
			constructor = cls.getDeclaredConstructor(argTypes);
			constructor.setAccessible(true);
		}

		return constructor;
	}

	/**
	 * 鑾峰緱绫荤殑鏂规硶
	 * 
	 * @param cls
	 * @param methodName
	 * @param argTypes
	 * @return
	 * @throws NoSuchMethodException
	 */
	public static Method getMethodIfAvailable(Class<?> cls, String methodName, Class<?>[] argTypes)
			throws NoSuchMethodException {
		Method method = null;

		try {
			method = cls.getDeclaredMethod(methodName, argTypes);
		} catch (NoSuchMethodException e) {
			if (cls.getSuperclass() != null) {
				return getMethodIfAvailable(cls.getSuperclass(), methodName, argTypes);
			} else {
				throw e;
			}
		}
		method.setAccessible(true);

		return method;
	}

	/**
	 * 鍙栧緱褰撳墠绾跨▼鐨勪笂涓嬫枃
	 * 
	 * @see Thread#getContextClassLoader()
	 * @return ClassLoader 褰撳墠绾跨▼绫诲姞杞藉櫒
	 */
	public static ClassLoader getDefaultClassLoader() {
		return Thread.currentThread().getContextClassLoader();
	}

	/**
	 * 鑾峰緱绯荤粺绫诲姞杞藉櫒
	 * 
	 * @see ClassLoader#getSystemClassLoader()
	 * @return
	 */
	public static ClassLoader getSystemClassLoader() {
		return ClassLoader.getSystemClassLoader();
	}

	/**
	 * 璋冪敤涓�涓璞＄殑涓�涓柟娉�
	 * 
	 * @param obj
	 * @param methodName
	 * @param args
	 * @return
	 * @throws NoSuchMethodException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public static Object invoke(Object obj, String methodName, Object[] args) throws NoSuchMethodException,
			IllegalArgumentException, IllegalAccessException, InvocationTargetException {
		Class<?>[] argTypes = new Class<?>[args.length];

		for (int i = 0; i < argTypes.length; i++) {
			argTypes[i] = args[i].getClass();
		}

		Method method = getMethodIfAvailable(obj.getClass(), methodName, argTypes);

		return method.invoke(obj, args);
	}

	/**
	 * 鑾峰緱涓�涓被鐨勬敞閲�
	 * 
	 * @param cls
	 * @param annoCls
	 * @return
	 */
	public static Annotation getAnnotationIfAvailable(Class<?> cls, Class<? extends Annotation> annoCls) {
		return cls.getAnnotation(annoCls);
	}

}
